import fg from "fast-glob";
import fs from "fs-extra";
import path from "path";
import { BaseTask, TaskResult } from "../../common/tasks/BastTask.js";
import { layatoolchain } from "../../layatoolchain.js";
import { appendMd5 } from "../../tools/vendor.js";
import { TFileNameMapper, TMd5Map } from "../../typings.js";
import { LayaEnv } from "../LayaEnv.js";

interface VersionNode {
    _f_?: string[],
    [folder: string]: VersionNode | string[] | undefined
}
declare type TVersionFile = { [ext: string]: VersionNode };

/**文件添加md5 */
export class LayaVersionedTask extends BaseTask<void> {
    async run(): Promise<TaskResult<void>> {
        let versionFile: string, nameMapper: TFileNameMapper;
        const historyVf = await fg('version.min*.json', { cwd: layatoolchain.vars.publishRoot });
        if (historyVf.length > 0) {
            console.log('version file already exists, skip');
            versionFile = historyVf[0];
            nameMapper = await fs.readJSON(versionFile);
        } else {
            const out = await this.versioned(layatoolchain.vars.publishRoot);
            // 写version文件
            const verJson = path.join(layatoolchain.vars.publishRoot, 'version.min.json');
            await fs.writeJSON(verJson, out.persistNameMapper);
            const md5Info = await appendMd5(verJson, LayaEnv.Md5Length, '');
            versionFile = md5Info.newFileName;
            nameMapper = out.nameMapper;
        }
        layatoolchain.vars.fileNameMapper = nameMapper;

        return { success: true, errorCode: 0, data: void 0 };
    }

    private async versioned(dir: string): Promise<{ nameMapper: TFileNameMapper, persistNameMapper: TVersionFile, md5Map: TMd5Map }> {
        const nameMapper: TFileNameMapper = {}, persistNameMapper: TVersionFile = {}, md5Map: TMd5Map = {};
        const ignore = ['**/*.js.map'];
        if (this.cmdOption.platform == 'web') ignore.push('**/*.html');
        else ignore.push('**/*.js');
        const files = await fg(['**/*'], { cwd: dir, ignore });
        for (const f of files) {
            const file = path.join(dir, f);
            const md5Info = await appendMd5(file, LayaEnv.Md5Length, '');
            md5Map[f] = md5Info.fileMd5;
            const d = f.includes('/') ? path.dirname(f) : '';
            nameMapper[f] = d != '' ? d + '/' + md5Info.newFileName : md5Info.newFileName;
            // 按类型>目录级别生成版本文件
            const ext = path.extname(f);
            let subMap = persistNameMapper[ext];
            if (subMap == null) persistNameMapper[ext] = subMap = {};
            const folders = d.split('/');
            const cnt = folders.length;
            let i = 0;
            while(i < cnt) {
                const folder = folders[i];
                let m = subMap[folder];
                if (m == null) subMap[folder] = m = {};
                subMap = m as VersionNode;
                i++;
            }
            let list = subMap._f_;
            if (list == null) subMap._f_ = list = [];
            list.push(path.basename(f).replace(ext, ''), md5Info.fileMd5.substring(0, LayaEnv.Md5Length));
        }
        return { nameMapper, persistNameMapper, md5Map };
    }
}
